﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Xml.Linq;
using System.Xml;
using System.IO;
using System.Xml.Serialization;

namespace Abyx.DebugHelper
{

    public class DebugHelper
    {
        private String iMessage;
        private ExceptionXElement iExceptionObject = null;
        private Object iDataObject;

        //Constructors
        private DebugHelper()
        {
        }
        public DebugHelper(String Message,
                                Exception ExceptionObject,
                                Object DataObject)
        {
            this.iMessage = Message;
            if (ExceptionObject != null)
            {
                this.iExceptionObject = new ExceptionXElement(ExceptionObject);
            }
            if (DataObject != null)
            {
                this.iDataObject = DataObject;
            }
        }

        //XML Generation Method
        public String GetSerializedXML()
        {
            
            // Create the xml document container
            XmlDocument doc = new XmlDocument();

            // Create the XML Declaration, and append it to XML document
            XmlDeclaration dec = doc.CreateXmlDeclaration("1.0", null, null);
            //doc.AppendChild(dec);
            
            // Create the root element
            XmlElement root = doc.CreateElement("DebugReport");
            doc.AppendChild(root);

            //Create Error Message element
            XmlAttribute erMsg = doc.CreateAttribute("ErrorMessage");
            erMsg.InnerText = this.iMessage;

            //Create Exception object data element
            XmlElement erObject = doc.CreateElement("ExceptionObject");
            if (this.iExceptionObject != null)
            {
                erObject.InnerXml = this.iExceptionObject.ToString();
            }

            //Create data object element
            XmlElement erData = doc.CreateElement("DataObject");
            if (this.iDataObject != null)
            {
                //Serialize the data object and get its XML
                StringWriter sw = new StringWriter();
                XmlSerializer xs = new XmlSerializer(this.iDataObject.GetType());
                xs.Serialize(sw, this.iDataObject);
                XmlDocument nxDoc = new XmlDocument();
                nxDoc.LoadXml(sw.ToString());
                erData.InnerXml = nxDoc.DocumentElement.InnerXml;
            }

            //Append the elements to root
            root.Attributes.Append(erMsg);
            root.AppendChild(erObject);
            root.AppendChild(erData);


            return doc.OuterXml;
        }
    }

    /// <summary>Represent an Exception as XML data.</summary>
    public class ExceptionXElement : XElement
    {
        /// <summary>Create an instance of ExceptionXElement.</summary>
        /// <param name="exception">The Exception to serialize.</param>
        public ExceptionXElement(Exception exception)
            : this(exception, false)
        { }

        /// <summary>Create an instance of ExceptionXElement.</summary>
        /// <param name="exception">The Exception to serialize.</param>
        /// <param name="omitStackTrace">
        /// Whether or not to serialize the Exception.StackTrace member
        /// if it's not null.
        /// </param>
        public ExceptionXElement(Exception exception, bool omitStackTrace)
            : base(new Func<XElement>(() =>
            {
                // Validate arguments

                if (exception == null)
                {
                    throw new ArgumentNullException("exception");
                }

                // The root element is the Exception's type

                XElement root = new XElement
                    (exception.GetType().ToString());

                if (exception.Message != null)
                {
                    root.Add(new XElement("Message", exception.Message));
                }

                // StackTrace can be null, e.g.:
                // new ExceptionAsXml(new Exception())

                if (!omitStackTrace && exception.StackTrace != null)
                {
                    root.Add
                    (
                        new XElement("StackTrace",
                            from frame in exception.StackTrace.Split('\n')
                            let prettierFrame = frame.Substring(6).Trim()
                            select new XElement("Frame", prettierFrame))
                    );
                }

                //// Data is never null; it's empty if there is no data
                //if (exception.Data.Count > 0)
                //{
                //    root.Add
                //    (
                //        new XElement("Data",
                //            from entry in
                //                exception.Data.Cast<DictionaryEntry>()
                //            let key = entry.Key.ToString()
                //            let value = (entry.Value == null) ?
                //                "null" : entry.Value.ToString()
                //            select new XElement(key, value))
                //    );
                //}

                // Add the InnerException if it exists

                if (exception.InnerException != null)
                {
                    root.Add
                    (
                        new ExceptionXElement
                            (exception.InnerException, omitStackTrace)
                    );
                }

                return root;
            })())
        { }
    }

    

}




